package fileshare.network;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;
import java.io.File;

import fileshare.control.preferque;
import fileshare.control.timerthread;
import fileshare.datastructure.ipinfo;
import fileshare.fileprocessing.AcessTextFile;
import fileshare.fileprocessing.CutJoinFile;
import fileshare.fileprocessing.ParseTracker;
import fileshare.fileprocessing.bitmapvector;
import fileshare.fileprocessing.log;
/**
 * @author HONGJIE
 *
 */
public class peerProcess
{

	

	
	
	public static boolean completeflag=false;
	public static int self_port=-1;//own port number
	public static preferque prq=null;
	/*
	 * the peer's own peer id in string
	 */
	public static String str_peerid=null;//
	public static boolean XCombine=false;
	/**
	 * peer's own int peerid
	 */
	public static boolean sendsig[];
	public static int self_peerid;
	public static int comflag;
	public static int self_index=0;
	public static int totalpeerno=0;
	// prefer peer number
	public static int NumberOfPreferred=-1;
	//update opt time
	public static int OptUnchokeinterval=-1;
	//update prefer time
	public static int Unchokeinterval=-1;
	public static long piecesize=-1;
	public static long remainsize;
	public static String filename;
	public static String realfilename;
	public static String ext;
	public static long filesize=-1;//the length of total file
	public static long piecenumber=-1;//how many pieces it is devided
	public static int []bitmap;//the bitmap needed
	/**
	 * the bits that has been requested
	 */
	public static int []bitreqsta;//the bits that has been requested
	public static int []unchoke;//the unchoke queue
	public static int []unchokeme=new int[7];//the peers that unchokeme//newchange
	public static int []interested;//the interested queue
	public static int []compeer=new int[7];
	public static int optimistic=-1;
	public static String filePath ="CEN5501C\\"; 
	public static String dirname;

	
	public static AcessTextFile peerip_container=new AcessTextFile();
	public static volatile  bitmapvector mapvector=null;//the bitmap container for the connecting peers
		
	
	public static void main(String args[])throws Exception
	{
		//boolean k=checkcomp(1);
		str_peerid=args[0];
		peerProcess p1=new peerProcess();
		
		ServerSocket ss;
		peerip_container.readorder();//iniitialzie the container now it contains every peer's 
		p1.initializepeer(); //initialize the parameter used dealing with ip                          //ip information
	

		
		
				for(int i=1;i<self_index;i++)
				{
					ipinfo ahead=peerip_container.getipinfobyindex(i);
					String ipout=ahead.ipaddress;
					
					int portout=ahead.portnumber;
				sendoutconnection(ipout,portout,ahead.peeridinfo,p1);
					
				log.writelog("out of this while");
				}
		
		
		try{
		Socket s = null;
		ss = new ServerSocket(self_port);//make a waiting socket server
	
	timerthread timer=new timerthread(1,Unchokeinterval);//1 means prefer change
		timerthread timer2=new timerthread(2,OptUnchokeinterval);//2 means opt change
	log.writelog("listenning at port"+self_port);
		//incomming connections
		while(true)//here this function is used to listen to outsider connection
		{
			log.writelog("waiting for client");
			Thread.sleep(100);
			
			s=ss.accept();
			
			if(s!=null)
			{
				log.writelog("peer comes in"+s);
				//create a new thread for every peer connecting in with the socket created here
			 taskthread connect=new taskthread(s,p1);
			 Thread serverthread= new Thread(connect);
			 serverthread.start();
			 s=null;
			}
		}
		}catch(Exception e){ e.printStackTrace();log.getExceptionTrace(e);}finally{
			
		}

	} 
	
	public static taskthread connectpeers(String ip,int port,peerProcess p1)throws Exception
	
	{
		taskthread t=new taskthread(ip,port,p1);
		return t;
	}
	
	public static taskthread sendoutconnection(String ip,int po,String targetpeer,peerProcess p1)throws Exception
	{
		boolean isend=true;

		// outcomming connection
		//try {
			taskthread ta=new taskthread(ip,po,p1);//try to connect the 8080 port running on the localhost
			if(ta.threadsock!=null)
				
				{System.out.print("sucess to connect other peer!" + ta.threadsock);
				String content="make a connection to"+targetpeer;
				log.write2log(content);
				}
			Thread startit=new Thread(ta);
			startit.start();
			
		
		
		if(ta!=null)
			return ta;
		else {System.out.println("taskthread created failed");return null;}
	}
	public static void updateprefer()
	{
		//if the file is complete
		//then chose 2 peer randomly from the interested queue
		//put them in temporary preferreed queue
		//check the current prefered ,check those peers who are not in the temporary queue
		//evict them by sendmsg(choke)
		//check the temporary preffere queue 
		//if they are in the choke list
		//sendmsg (unchoke)
	   // 
		//
		//if the file is not complete
		//caculate the download rate from the interested queue,
		//{ maintain a queue called download queue [6],initalize t0 0,when receive a piece 
		//in creasing the correspongding peer inside by +1 ,after the update prefer,zero it.
		//
		//}
		//
		
		
		//if the file is not comple 
	}
	public static void receiveconnection()
	{
		
	}
	
	
	public static void filecomplete()
	{
	
	}
	/**
	 * check the unchoke queue and optimistic queue to see whether this peer exits in,
	 * if yes then unchoke 
	 * @param peerid
	 * @return
	 */
	public static boolean whetherchoke(int peerid)
	{
		int chokevalue=prq.checkChoke(peerid);
		if (chokevalue>=1)
			return false;
			else
				return true;
		/*boolean choke=true;
		for(int i=0;i<2;i++) //here the 2 might be changed to other parameter need update
			{if(unchoke[i]==peerid)choke=false;}
		if(optimistic==peerid)
			choke=false;
		return choke;*/
			
		
				
	}
/*public static void refreshChokelist( int pid)
{
	unchoke[pid]=
}*/
	
	public  void initializepeer()throws Exception
	{
		
		
		/*System.out.println("input the peerid");
		  BufferedReader stdin = new BufferedReader(new InputStreamReader(
					System.in));
		  str_peerid=stdin.readLine();
		
		  if(str_peerid.length()!=0)  
		  {     
			  System.out.println("you input"+str_peerid);  
		  }*/
		//get the tracker information from Common.cfg
		  ParseTracker.getTracker();
		  //compute the piecenumber and remain size
		  getfileinfo();
		  //initialize the filename;
		 filename= "CEN5501C//"+realfilename;
		  ipinfo selfinf=peerip_container.getipinfo(str_peerid);
		  self_peerid=Integer.parseInt(str_peerid,10);
		  dirname="peer_"+self_peerid;
		  //generate the subdirectory
		  File dir=new File(dirname);
		  if(!dir.exists())
			  dir.mkdir();
		  self_port=selfinf.portnumber;
		  self_index=selfinf.index;
		  totalpeerno=peerip_container.ipcount;
		  mapvector=new bitmapvector(totalpeerno);
		  interested=new int [totalpeerno+1];
		  bitreqsta=new int [(int)piecenumber+1];
		  sendsig=new boolean[7];
		  for(int i=0;i<totalpeerno+1;i++)
		  {
			  interested[i]=-1;
			  unchokeme[i]=0;//initialize the peer list who unchoke me 
			  compeer[i]=0;
			  sendsig[i]=false;
		  }
		  comflag=selfinf.filestat;
		  if (comflag==1)//if the file has exited then get the infomation
		  {
			  completeflag=true;
			  compeer[self_index]=1;
			  
			  
			 // getfileinfo();
			  //if the file is complete then sperate it into pieces
			 // Separator separator = new Separator();
			  //separate the file and return the piece number
			 // int seperate=separator.seperate((int)piecesize);
			 // if(seperate!=0)
				////  piecenumber=seperate;
			 // System.out.println(" the seperate is "+seperate);
			  CutJoinFile.seperate((int)piecesize);
			  bitmap=new int[(int)piecenumber];
			  for(int i=0;i<(int)piecenumber;i++)
			  {
				  bitmap[i]=1;
				  
			  }
			  System.out.println("initialization  mapvecotr's bitmap");
			  mapvector.bitmapadd(bitmap, self_index);
			  //log=new File(str_peerid);
			  
		  }
		  else//initialize the bitmap
		  {
			/*  piecenumber=filesize/piecesize;
				long remain=filesize-piecenumber*piecesize;
				if(remain>0)
					piecenumber=piecenumber+1;
				long lastpiece=remain;
				remainsize=remain;*/
			  
			  bitmap=new int[(int)piecenumber];
		  for(int i=0;i<(int)piecenumber;i++)
		  {
			  bitmap[i]=0;
			  bitreqsta[i]=0;
			  
		  }
		  mapvector.bitmapadd(bitmap, self_index);
		  
		  }
		  
		  
		 prq= new preferque();  
		  
	}
	private static void getfileinfo()
	{
		
			
			piecenumber=filesize/piecesize;
			long remain=filesize-piecenumber*piecesize;
			if(remain>0)
				piecenumber=piecenumber+1;
			remainsize=remain;
			System.out.println("filesize :"+filesize+" piecenumber: "+piecenumber);
		
		
		
		
	}
	/**
	 * test whether a special piece is received
	 * @param r_index the piece number checked
	 * @return 0: already has it try another 1: ok it is not yet received 2: the file is complete now
	 */
	public static int stillno(int r_index)//test whether a special piece is received
	{	
		boolean finsh=false;
		for(int j=0;j<piecenumber;j++)
		{
			if(bitmap[j]!=1)
			{
				finsh=false;
				break;
			}
			finsh=true;
				
		}
		if(finsh)
			{ completeflag=true;return 2;}//the file is complete now no need to request
		if(bitmap[r_index]==0)
			return 1; //ok the piece requested is empty
		else return 0;//no try another piece
		
	}
	//write the log file
	public static void writefile(String content)
	{
		
	}
	/**
	 * check whether all the peers have finished the file sharing
	 * @return
	 */
	public static boolean ifallpeerfi()
	{
		if(XCombine)
			return true;
		
		boolean all=checkallpeerandcombine();
		if(comflag==1&&all)
			{ XCombine=true;return true;}
		if(all&&comflag!=1)//do combine
		{
			CutJoinFile.combine();
			XCombine=true;
			return true;
		}
		else
			return false;
	}
	public static boolean checkallpeerandcombine()
	{	boolean all=true;
		for(int i=1;i<7;i++)
		{
			//checkcomp(i);
			/*if(!checkcomp(i))
				return false;*/
			if(compeer[i]==0)
				return false;
			
		}
		return all;
	}
	/**
	 * 
	 * @param peerindex the peer index to be cheked
	 * @return true: the checked peer has a complete file already false:not complete
	 */
	public static boolean checkpeerstat(int peerindex)
	{	boolean all=true;
		
			if(compeer[peerindex]==0)
				return false;
			else
		    return all;
	}
	
	public static void changecompeer(int targetid)
	{
		compeer[targetid]=1;
	}
	
	public static long dircap(String dir)
	{
		dir="src//"+dir;
		long length=0;
		File fdir=new File(dir);
		if(fdir.isDirectory())
		{
			File flist[]=fdir.listFiles();
			for(int i=0;flist!=null&&i<flist.length;i++)
				length=length+flist[i].length();
		}
		
		
		return length;
		
	}
	public static boolean checkcomp(int index)
	{
		long len=dircap("peer_100"+index);
		log.writelog("length is"+len);
		if(len==filesize)
			return true;
		else
			return false;
		
	}
	public static boolean checksendsig(int targetpeerindex)
	{
		return sendsig[targetpeerindex];
	}
	public static void changesendsig(int targetpeerindex)
	{
		sendsig[targetpeerindex]=true;
	}
	
}
